package org.shiro.demo.service.realm;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.shiro.demo.entity.Administrator;
import org.shiro.demo.entity.Permission;
import org.shiro.demo.entity.Role;
import org.shiro.demo.entity.Sms;
import org.shiro.demo.entity.User;
import org.shiro.demo.service.IAdminService;
import org.shiro.demo.service.IBaseService;
import org.shiro.demo.service.IRoleService;
import org.shiro.demo.service.IUserService;

/**
 * 自定义的指定Shiro验证用户登录的类
 * 
 * @author Chinesejie
 * 
 */
public class ShiroDbRealm extends AuthorizingRealm {

	// @Resource(name="userService")
	private IUserService userService;

	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	private IAdminService adminService;

	public void setAdminService(IAdminService adminService) {
		this.adminService = adminService;
	}

	private IRoleService roleService;

	public void setRoleService(IRoleService roleService) {
		this.roleService = roleService;
	}

	/**
	 * 为当前登录的Subject授予角色和权限
	 * 
	 * @see 经测试:本例中该方法的调用时机为需授权资源被访问时
	 * @see 经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例未启用AuthorizationCache
	 * @see web层可以有shiro的缓存，dao层可以配有hibernate的缓存（后面介绍）
	 */
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("来查权限数据库了。。。");
		// 获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()
		Object account = (Object) super.getAvailablePrincipal(principals);
		List<String> roles = new ArrayList<String>();
		List<String> permissions = new ArrayList<String>();
		if (account instanceof Administrator) {// 管理员
			// // 直接 转换
			Administrator serializable_user = (Administrator) account;
			// serializable_user经过序列化了,序列化的时候 没有对 role 进行 序列化。。所以
			// 如果下面执行serializable_user.getRoles()会报错..
			// 必须 从数据库重新获得
			Administrator user = adminService.getByPhone(serializable_user.getPhone());
			if (user != null) {
				// 实体类User中包含有用户角色的实体类信息
				if (user.getRoles() != null && user.getRoles().size() > 0) {
					// 获取当前登录用户的角色
					for (Role role : user.getRoles()) {
						roles.add(role.getName());
						// 实体类Role中包含有角色权限的实体类信息
						if (role.getPmss() != null && role.getPmss().size() > 0) {
							// 获取权限
							for (Permission pmss : role.getPmss()) {
								if (!StringUtils.isEmpty(pmss.getPermission())) {
									permissions.add(pmss.getPermission());
								}
							}
						}
					}
				}
			}

			// 为当前用户设置角色和权限
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			info.addRoles(roles);
			info.addStringPermissions(permissions);

			return info;
		} else {// 0 号角色。。顾客 、、赋予基本权限... sms 也属于用户 , mob 也属于用户
			Role customerRole = roleService.getByName("customer");// 可能不存在？？？
																	// 那就是数据被删了
			roles.add(customerRole.getName());
			// 实体类Role中包含有角色权限的实体类信息
			if (customerRole.getPmss() != null && customerRole.getPmss().size() > 0) {
				// 获取权限
				for (Permission pmss : customerRole.getPmss()) {
					if (!StringUtils.isEmpty(pmss.getPermission())) {
						permissions.add(pmss.getPermission());
					}
				}
			} else {
				throw new AuthorizationException();
			}
			// 为当前用户设置角色和权限
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			info.addRoles(roles);
			info.addStringPermissions(permissions);

			return info;
		}
	}

	@Resource(name = "baseService")
	private IBaseService baseService;

	/**
	 * 验证当前登录的Subject
	 * 
	 * @see 经测试:本例中该方法的调用时机为LoginController.login()方法中执行Subject.login()时
	 */
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		// 获取基于用户名和密码的令牌
		// 实际上这个authcToken是从LoginController里面currentUser.login(token)传过来的
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		String tokens[] = token.getUsername().split(";");
		// 准备好 Principal..我们只有两种 基类。后期 不排除单独把店长当成一个基类。
		Administrator admin = null;
		User user = null;
		// 从数据库中查询用户用信息
		String tokenPrefix = tokens[0];
		if (("admin").equals(tokenPrefix)) {
			admin = adminService.getByPhone(tokens[1]);
			if (admin != null) {
				// 此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息.
				return new SimpleAuthenticationInfo(admin, admin.getPassword(), getName());
			} else {
				// 没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
				return null;
			}
		} else if (("user").equals(tokenPrefix)) {
			user = userService.getByPhone(tokens[1]);
			if (user != null) {
				// 此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息
				return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
			} else {
				// 没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
				return null;
			}
		}
		/**
		 * 验证码登陆删除。不能使用验证码 登陆
		 */
		// else if (("sms").equals(tokenPrefix)) {// 验证码
		// // ("sms").equals(tokenPrefix)
		// Sms sms = baseService.getById(Sms.class,
		// token.getUsername().split(";")[1]);
		// if (sms != null && sms.getType().equals("Login")) {// 必须是登陆的type
		// // 此处无需比对,比对的逻辑Shiro会做,我们只需返回一个和令牌相关的正确的验证信息
		// return new SimpleAuthenticationInfo("sms;" + sms.getPhone(),
		// sms.getCode(), getName());
		// } else {
		// //
		// 没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
		// return null;
		// }
		// }
		else {// 验证码 ("mob").equals(tokenPrefix)
				// return new SimpleAuthenticationInfo(token.toString(), "1",
				// getName());
			return null;
		}
	}

	/**
	 * 
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(Object principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {

				cache.remove(key);
			}
		}
	}

	public void clearSomeoneCachedAuthorizationInfo(String someone) {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();

		Object k = null;
		if (cache != null) {
			for (Object key : cache.keys()) {
				if (key.toString().equals(someone)) {
					k = key;
					break;
				}
			}
			cache.remove(k);
		}
	}

}
